﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WI_E2_Parser
{
    class Ranker
    {
        Indexer index;
        int crawlCount;
        List<Calculation> calculations = new List<Calculation>();
        List<KeyValuePair<Term, double>> wtResultList = new List<KeyValuePair<Term, double>>();
        List<KeyValuePair<Term, double>> wtNormalizedList = new List<KeyValuePair<Term, double>>();

        List<resultHolder> docWrtList = new List<resultHolder>(); 


        double wtTemp = 0;
        double pageWTTemp = 0;


        public Ranker(Indexer index, int crawlCount)
        {
            this.index = index;
            this.crawlCount = crawlCount;
        }

        public void calculateTF()
        {
            foreach (Term term in index.termIndex)
            {
                Calculation calc = new Calculation(term.termName);

                foreach (KeyValuePair<int, int> freq in term.frequency)
                {
                    double result = 1 + Math.Log10(freq.Value);
                    calc.addToTf(freq.Key, result);
                }
                this.calculations.Add(calc);
            }
        }

        public void rankIndex()
        {
            this.calculateTF();
        }

        static int CompareByKey(resultHolder a, resultHolder b)
        {
            return a.score.CompareTo(b.score);
        }

        public void search(string query)
        {
            Tokenizer tok = new Tokenizer();

            List<string> queryTokens = tok.tokenize(query);

            List<Term> results = new List<Term>();
            Stemmer stem = new Stemmer();

            foreach (string token in queryTokens.Distinct())
            {
                
                string stemmedToken = stem.stem(token);
                List<Term> selected = this.index.termIndex.Where(x => x.termName.Equals(stemmedToken)).ToList();

                results.AddRange(selected);
            }

            foreach (Term t in results)
            {
                int tf = queryTokens.Count(x => x.Equals(t.termName));

                int pageCount = t.frequency.Count();
                
                double idf = Math.Log10(crawlCount / pageCount);

                double wt = tf * idf;

                wtResultList.Add(new KeyValuePair<Term, double>(t, wt));

                wtTemp = wtTemp + Math.Pow(wt, 2);

                foreach (KeyValuePair<int,int> freq in t.frequency)
                {
                    int pageID = freq.Key;
                    int termFreq = freq.Value;
                    double temp_wt = 1.0 + Math.Log10(termFreq);

                    List<resultHolder> tmp = docWrtList.Where(x => x.pageName.Equals(index.crawledPages[pageID])).ToList();

                    if (tmp.Count <= 0)
                    {
                        resultHolder res = new resultHolder();
                        res.pageName = index.crawledPages[pageID];
                        res.wtResult.Add(new KeyValuePair<Term, double>(t, temp_wt));
                        docWrtList.Add(res);
                    }
                    else
                    {
                        tmp[0].wtResult.Add(new KeyValuePair<Term, double>(t, temp_wt));
                    }
                }
            }

            double pageDocLenth = Math.Sqrt(pageWTTemp);
           
            double docLenth = Math.Sqrt(wtTemp);

            foreach (KeyValuePair<Term, double> wtResult in wtResultList)
            {
                wtNormalizedList.Add(new KeyValuePair<Term, double>(wtResult.Key, wtResult.Value / docLenth));
            }

            foreach (resultHolder res in docWrtList)
            {
                List<KeyValuePair<Term, double>> normPageWT = res.getNormalizedList();

                double score = 0;

                foreach (KeyValuePair<Term, double> normPage in normPageWT)
                {
                    score += wtNormalizedList.Where(x => x.Key.Equals(normPage.Key)).ToList()[0].Value * normPage.Value;
                }

                res.score = score;
            }

            docWrtList.Sort(CompareByKey);

            int c = 1;

            foreach (resultHolder res in docWrtList)
            {
                Console.WriteLine(c + ": " + res.pageName);
                Console.WriteLine("score: " + res.score);
                c++;
            }

            if (docWrtList.Count <= 0)
            {
                Console.WriteLine("Sorry, no results");
            }
            
            Console.ReadLine();
        }
    }
}
